`ifndef LILYRISCV_V
`define LILYRISCV_V


`include "defines.v"

module LilyRiscv(
	input  wire 		  				clk   		,
	input  wire 		  				rstn		,

	// to rom
	output wire[`InstAddrWidth - 1 : 0]	inst_addr_o	,
	// from rom
	input  wire[`InstWidth - 1 : 0]    	inst_i,

	// from  mem
	output  wire 	   	  mem_rreq_o		,
	output  wire[31:0]   mem_raddr_o		,
	input	wire[31:0]	  mem_rdata_i		,	
	// to mem
	output  wire	 	  mem_wreq_o		,
	output  wire[3:0]   mem_wsel_o		,
	output  wire[31:0]  mem_waddr_o		,
	output  wire[31:0]  mem_wdata_o			
);

// // pc to instf
// wire[`InstAddrWidth - 1 : 0] pc_reg_pc_o;

// // instf to instf_id
// wire[`InstAddrWidth - 1 : 0] instf_inst_addr_o;
// wire[`InstWidth - 1 : 0] instf_if_inst_o;	

// pc_reg to rom / instf_id
wire[`InstAddrWidth - 1 : 0] pc_reg_pc_o;
assign inst_addr_o = pc_reg_pc_o;

// instf_id to id
wire[`InstAddrWidth - 1 : 0] instf_id_inst_addr_o;
wire[`InstWidth - 1 : 0] instf_id_inst_o;	

// id to regs
wire[`RegAddrWidth - 1 : 0] id_reg1_raddr_o;
wire[`RegAddrWidth - 1 : 0] id_reg2_raddr_o;

// id to id_ex
wire[`InstAddrWidth - 1 : 0] id_inst_addr_o;
wire[`InstWidth - 1 : 0] id_inst_o;
wire[`RegAddrWidth - 1 : 0]  id_reg_waddr_o;
wire       					id_reg_wen_o;
wire[`OPWidth - 1 : 0] id_op1_o;
wire[`OPWidth - 1 : 0] id_op2_o;
wire[`OPWidth - 1 : 0] id_op1_jump_o;
wire[`OPWidth - 1 : 0] id_op2_jump_o;

// regs to id
wire[`RegDataWidth - 1 : 0] regs_reg1_rdata_o;
wire[`RegDataWidth - 1 : 0] regs_reg2_rdata_o;

// id_ex to ex
wire[`InstAddrWidth - 1 : 0] id_ex_inst_addr_o;
wire[`InstWidth - 1 : 0] id_ex_inst_o;
wire[`RegAddrWidth - 1 : 0]  id_ex_reg_waddr_o;
wire       id_ex_reg_wen_o;
wire[`OPWidth - 1 : 0] id_ex_op1_o;
wire[`OPWidth - 1 : 0] id_ex_op2_o;
wire[`OPWidth - 1 : 0] id_ex_op1_jump_o;
wire[`OPWidth - 1 : 0] id_ex_op2_jump_o;

// ex to regs
wire[`RegAddrWidth - 1 : 0]  ex_waddr_o;
wire[`RegDataWidth - 1 : 0] ex_wdata_o;
wire       					ex_wen_o;

// ex to ctrl
wire[`InstAddrWidth - 1 : 0] ex_jump_addr_o;
wire  	   					ex_jump_en_o;
wire 	   					ex_hold_flag_o;

// ctrl to pc_reg
wire[`InstAddrWidth - 1 : 0] ctrl_jump_addr_o;
wire  	   ctrl_jump_en_o;
// ctrl to instf_id, id_ex
wire 	   ctrl_hold_flag_o;		

pc_reg u_pc_reg(
	.clk			(clk				),
	.rstn			(rstn				),
	.jump_addr_i	(ctrl_jump_addr_o	),
	.jump_en		(ctrl_jump_en_o		),		
	.pc_o   		(pc_reg_pc_o		)
);

// instf u_instf(
// 	.pc_addr_i			(pc_reg_pc_o		),
// 	.rom_inst_i			(inst_i				),
// 	.instf2rom_addr_o	(inst_addr_o		), 
// 	.inst_addr_o		(instf_inst_addr_o	), 
// 	.inst_o         	(instf_if_inst_o	)
// );

instf_id u_instf_id(
	.clk			(clk		      		),
	.rstn			(rstn		      		),
	.hold_flag_i	(ctrl_hold_flag_o 		),
	.inst_addr_i	(pc_reg_pc_o   			), 
	.inst_i			(inst_i        			),  
	.inst_addr_o	(instf_id_inst_addr_o	), 
	.inst_o         (instf_id_inst_o	  	)
);

id u_id(
	.inst_addr_i	(instf_id_inst_addr_o	),
	.inst_i			(instf_id_inst_o		),
	.reg1_raddr_o	(id_reg1_raddr_o		),
	.reg2_raddr_o	(id_reg2_raddr_o		),
	.reg1_rdata_i	(regs_reg1_rdata_o		),
	.reg2_rdata_i	(regs_reg2_rdata_o		),
	.inst_addr_o	(id_inst_addr_o			),	
	.inst_o			(id_inst_o				),
	.reg_waddr_o	(id_reg_waddr_o			),	
	.reg_wen_o      (id_reg_wen_o			),
	.op1_o			(id_op1_o				),	
	.op2_o			(id_op2_o				),
	.op1_jump_o		(id_op1_jump_o			),
	.op2_jump_o		(id_op2_jump_o			),
	// to mem
	.mem_rreq_o	(mem_rreq_o		),
	.mem_raddr_o(mem_raddr_o		)
);

regs u_regs(
	.clk			(clk					),
	.rstn			(rstn					),
	.reg1_raddr_i	(id_reg1_raddr_o		),
	.reg2_raddr_i	(id_reg2_raddr_o		), 
	.reg1_rdata_o	(regs_reg1_rdata_o		),
	.reg2_rdata_o	(regs_reg2_rdata_o		),
	.waddr_i		(ex_waddr_o				),
	.wdata_i		(ex_wdata_o				),
	.wen_i   		(ex_wen_o				)
);

id_ex u_id_ex(
	.clk			(clk				),
	.rstn			(rstn				),
	.inst_addr_i	(id_inst_addr_o		),
	.inst_i			(id_inst_o			),
	.reg_waddr_i	(id_reg_waddr_o		),	
	.reg_wen_i		(id_reg_wen_o		),
	.op1_i			(id_op1_o			),	
	.op2_i			(id_op2_o			),
	.op1_jump_i		(id_op1_jump_o		),
	.op2_jump_i		(id_op2_jump_o		),
	.hold_flag_i	(ctrl_hold_flag_o 	),
	.inst_addr_o    (id_ex_inst_addr_o	),
	.inst_o			(id_ex_inst_o		),
	.reg_waddr_o	(id_ex_reg_waddr_o	),	
	.reg_wen_o		(id_ex_reg_wen_o	),
	.op1_o			(id_ex_op1_o		),		
	.op2_o			(id_ex_op2_o		),
	.op1_jump_o		(id_ex_op1_jump_o	),		
	.op2_jump_o		(id_ex_op2_jump_o	)
);

ex u_ex(
	.inst_addr_i	(id_ex_inst_addr_o	),
	.inst_i			(id_ex_inst_o		),	
	.reg_waddr_i	(id_ex_reg_waddr_o	),
	.reg_wen_i		(id_ex_reg_wen_o	),
	.op1_i			(id_ex_op1_o		),
	.op2_i			(id_ex_op2_o		),
	.op1_jump_i		(id_ex_op1_jump_o	),		
	.op2_jump_i		(id_ex_op2_jump_o	),
	.waddr_o		(ex_waddr_o			),
	.wdata_o		(ex_wdata_o			),	
	.wen_o       	(ex_wen_o			),
	.jump_addr_o	(ex_jump_addr_o		),		
	.jump_en_o		(ex_jump_en_o		),		
	.hold_flag_o	(ex_hold_flag_o		),	

	.mem_wreq_o	(mem_wreq_o		),
	.mem_wsel_o(mem_wsel_o		),
	.mem_waddr_o(mem_waddr_o		),
	.mem_wdata_o(mem_wdata_o		),	

	.mem_rdata_i(mem_rdata_i		)	
);

ctrl u_ctrl(
	.jump_addr_i	(ex_jump_addr_o		),
	.jump_en_i		(ex_jump_en_o		),
	.hold_flag_i	(ex_hold_flag_o		),
	.jump_addr_o	(ctrl_jump_addr_o	),
	.jump_en_o		(ctrl_jump_en_o		),
	.hold_flag_o	(ctrl_hold_flag_o	)	
);

endmodule


`endif // LILYRISCV_V